home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Source.bin / WrappingLabel.java < prev    next >
Text File  |  1998-08-21  |  13KB  |  459 lines

  1. package symantec.itools.awt;
  2.  
  3. import java.awt.Canvas;
  4. import java.awt.Graphics;
  5. import java.awt.FontMetrics;
  6. import java.awt.Dimension;
  7. import java.awt.Label;
  8. import java.beans.PropertyVetoException;
  9. import java.beans.PropertyChangeListener;
  10. import java.beans.VetoableChangeListener;
  11. import java.beans.PropertyChangeEvent;
  12. import symantec.itools.beans.VetoableChangeSupport;
  13. import symantec.itools.beans.PropertyChangeSupport;
  14.  
  15. //  05/13/95    CAR Added resize and reshape methods.
  16. //    06/01/97    RKM    Updated to support Java 1.1
  17. //    06/11/97    LAB    Polished, and added listener registration functions.
  18. //  07/24/97    CAR marked fields transient as needed
  19.  
  20. /**
  21.  * This class implements a multiple-line text label.
  22.  * It displays text on one or more lines, wrapping text
  23.  * as needed to fit in the available horizontal space.
  24.  *
  25.  * @version 1.1, June 11, 1997
  26.  *
  27.  * @author    Symantec
  28.  */
  29. public class WrappingLabel extends Canvas implements AlignStyle
  30. {
  31.     /**
  32.      * Constructs a default wrapping label. Default values are an empty text string
  33.      * and left alignment.
  34.      */
  35.     public WrappingLabel()
  36.     {
  37.         this("");
  38.     }
  39.  
  40.     /**
  41.      * Constructs a wrapping label that displays the specified string.
  42.      * The label will default to left alignment.
  43.      *
  44.      * @param s string to be displayed in label
  45.      */
  46.     public WrappingLabel(String s)
  47.     {
  48.         this(s, WrappingLabel.ALIGN_LEFT);
  49.     }
  50.  
  51.     /**
  52.      * Constructs wrapping label with the specified text and alignment.
  53.      *
  54.      * @param s the string to be displayed in label
  55.      * @param a the alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  56.      *
  57.      * @see symantec.itools.awt.AlignStyle
  58.      * @see symantec.itools.awt.AlignStyle#ALIGN_LEFT
  59.      * @see symantec.itools.awt.AlignStyle#ALIGN_CENTERED
  60.      * @see symantec.itools.awt.AlignStyle#ALIGN_RIGHT
  61.      */
  62.     public WrappingLabel(String s, int a)
  63.     {
  64.         try
  65.         {
  66.             setText(s);
  67.         }
  68.         catch(PropertyVetoException veto) {};
  69.  
  70.         try
  71.         {
  72.             setAlignStyle(a);
  73.         }
  74.         catch(PropertyVetoException veto) {};
  75.     }
  76.  
  77.  
  78.     //--------------------------------------------------
  79.     // accessor members
  80.     //--------------------------------------------------
  81.  
  82.     /**
  83.      * Gets the current text alignment setting.
  84.      *
  85.      * @return the current alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  86.      * @see #setAlignStyle
  87.      * @see symantec.itools.awt.AlignStyle
  88.      * @see symantec.itools.awt.AlignStyle#ALIGN_LEFT
  89.      * @see symantec.itools.awt.AlignStyle#ALIGN_CENTERED
  90.      * @see symantec.itools.awt.AlignStyle#ALIGN_RIGHT
  91.      */
  92.     public int getAlignStyle()
  93.     {
  94.         return align;
  95.     }
  96.  
  97.     /**
  98.      * Sets the text alignment.
  99.      *
  100.      * @param newAlignStyle the new alignment style, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  101.      * @see #getAlignStyle
  102.      * @see symantec.itools.awt.AlignStyle
  103.      * @see symantec.itools.awt.AlignStyle#ALIGN_LEFT
  104.      * @see symantec.itools.awt.AlignStyle#ALIGN_CENTERED
  105.      * @see symantec.itools.awt.AlignStyle#ALIGN_RIGHT
  106.      * @exception PropertyVetoException
  107.      * if the specified property value is unacceptable
  108.      */
  109.     public void setAlignStyle(int newAlignStyle)
  110.         throws PropertyVetoException
  111.     {
  112.         if (align != newAlignStyle)
  113.         {
  114.             Integer oldAlignStyleInt = new Integer(align);
  115.             Integer newAlignStyleInt = new Integer(newAlignStyle);
  116.  
  117.             vetos.fireVetoableChange("AlignStyle",oldAlignStyleInt,newAlignStyleInt);
  118.  
  119.             align = newAlignStyle;
  120.  
  121.             changes.firePropertyChange("AlignStyle",oldAlignStyleInt,newAlignStyleInt);
  122.  
  123.             repaint();
  124.         }
  125.     }
  126.  
  127.     /**
  128.      * Gets the current label text.
  129.      *
  130.      * @return the label's text string
  131.      * @see #setText
  132.      */
  133.     public String getText()
  134.     {
  135.         return text;
  136.     }
  137.  
  138.     /**
  139.      * Sets the label text.
  140.      *
  141.      * @param s the new label text
  142.      *
  143.      * @see #getText
  144.      * @exception PropertyVetoException
  145.      * if the specified property value is unacceptable
  146.      */
  147.     public void setText(String newText)
  148.         throws PropertyVetoException
  149.     {
  150.         if (!symantec.itools.util.GeneralUtils.objectsEqual(text,newText))
  151.         {
  152.             String oldText = text;
  153.  
  154.             vetos.fireVetoableChange("Text",oldText,newText);
  155.  
  156.             text = newText;
  157.  
  158.             changes.firePropertyChange("Text",oldText,newText);
  159.  
  160.             repaint();
  161.         }
  162.     }
  163.  
  164.     //--------------------------------------------------
  165.     // event methods
  166.     //--------------------------------------------------
  167.  
  168.  
  169.     //--------------------------------------------------
  170.     // class methods
  171.     //--------------------------------------------------
  172.  
  173.  
  174.     //--------------------------------------------------
  175.     // member methods
  176.     //--------------------------------------------------
  177.  
  178.     /**
  179.      * Returns an empty string.
  180.      * This is a standard Java AWT method which typically returns a string
  181.      * representing the state of this object.
  182.      *
  183.      * @return the empty string
  184.      */
  185.     public String paramString()
  186.     {
  187.         return "";
  188.     }
  189.  
  190.     /**
  191.      * Moves and/or resizes this component.
  192.      * This is a standard Java AWT method which gets called to move and/or
  193.      * resize this component. Components that are in containers with layout
  194.      * managers should not call this method, but rely on the layout manager
  195.      * instead.
  196.      *
  197.      * It is overridden here to re-wrap the text as necessary.
  198.      *
  199.      * @param x horizontal position in the parent's coordinate space
  200.      * @param y vertical position in the parent's coordinate space
  201.      * @param width the new width
  202.      * @param height the new height
  203.      */
  204.     public synchronized void reshape(int x, int y, int width, int height) {
  205.         super.reshape(x, y, width, height);
  206.         invalidate();
  207.         validate();
  208.         repaint();
  209.     }
  210.  
  211.     /**
  212.      * Resizes this component.
  213.      * This is a standard Java AWT method which gets called to
  214.      * resize this component. Components that are in containers with layout
  215.      * managers should not call this method, but rely on the layout manager
  216.      * instead.
  217.      *
  218.      * It is overridden here to re-wrap the text as necessary.
  219.      *
  220.      * @param width the new width, in pixels
  221.      * @param height the new height, in pixels
  222.      */
  223.     public synchronized void resize(int width, int height) {
  224.         super.resize(width, height);
  225.         invalidate();
  226.         validate();
  227.         repaint();
  228.     }
  229.  
  230.     /**
  231.      * Paints this component using the given graphics context.
  232.      * This is a standard Java AWT method which typically gets called
  233.      * by the AWT to handle painting this component. It paints this component
  234.      * using the given graphics context. The graphics context clipping region
  235.      * is set to the bounding rectangle of this component and its [0,0]
  236.      * coordinate is this component's top-left corner.
  237.      *
  238.      * @param g the graphics context used for painting
  239.      * @see java.awt.Component#repaint
  240.      * @see java.awt.Component#update
  241.      */
  242.     public void paint(Graphics g)
  243.     {
  244.         if (text != null)
  245.         {
  246.             int x, y;
  247.             int boundx, boundy;
  248.             Dimension d;
  249.             int fromIndex = 0;
  250.             int pos = 0;
  251.             int bestpos;
  252.             String largestString;
  253.             String s;
  254.  
  255.             // Set up some class variables
  256.             fm = getToolkit().getFontMetrics(getFont());
  257.             baseline = fm.getMaxAscent();
  258.  
  259.             // Get the maximum height and width of the current control
  260.             d = size();
  261.             boundx = d.width;
  262.             boundy = d.height;
  263.  
  264.             // X and Y represent the coordinates of the upper left portion
  265.             // of the next text line.
  266.             x = 0;
  267.             y = 0;
  268.  
  269.             // While we haven't passed the bottom of the label and we
  270.             // haven't run past the end of the string...
  271.             while ((y + fm.getHeight()) <= boundy && fromIndex != -1)
  272.             {
  273.                 // Automatically skip any spaces at the beginning of the line
  274.                 while (fromIndex < text.length() && text.charAt(fromIndex) == ' ')
  275.                 {
  276.                     ++fromIndex;
  277.                     // If we hit the end of line while skipping spaces, we're done.
  278.                     if (fromIndex >= text.length()) break;
  279.                 }
  280.  
  281.                 // fromIndex represents the beginning of the line
  282.                 pos = fromIndex;
  283.                 bestpos = -1;
  284.                 largestString = null;
  285.  
  286.                 while (pos >= fromIndex)
  287.                 {
  288.                     pos = text.indexOf(' ', pos);
  289.  
  290.                     // Couldn't find another space?
  291.                     if (pos == -1)
  292.                     {
  293.                         s = text.substring(fromIndex);
  294.                     }
  295.                     else
  296.                     {
  297.                         s = text.substring(fromIndex, pos);
  298.                     }
  299.  
  300.                     // If the string fits, keep track of it.
  301.                     if (fm.stringWidth(s) < boundx)
  302.                     {
  303.                         largestString = s;
  304.                         bestpos = pos;
  305.  
  306.                         // If we've hit the end of the string, use it.
  307.                         if (pos == -1) break;
  308.                     }
  309.                     else
  310.                     {
  311.                         break;
  312.                     }
  313.  
  314.                     ++pos;
  315.                 }
  316.  
  317.                 if (largestString == null)
  318.                 {
  319.                     // Couldn't wrap at a space, so find the largest line
  320.                     // that fits and print that.  Note that this will be
  321.                     // slightly off -- the width of a string will not necessarily
  322.                     // be the sum of the width of its characters, due to kerning.
  323.                     int totalWidth = 0;
  324.                     int oneCharWidth = 0;
  325.  
  326.                     pos = fromIndex;
  327.  
  328.                     while (pos < text.length())
  329.                     {
  330.                         oneCharWidth = fm.charWidth(text.charAt(pos));
  331.                         if ((totalWidth + oneCharWidth) >= boundx) break;
  332.                         totalWidth += oneCharWidth;
  333.                         ++pos;
  334.                     }
  335.  
  336.                     drawAlignedString(g, text.substring(fromIndex, pos), x, y, boundx);
  337.                     fromIndex = pos;
  338.                 }
  339.                 else
  340.                 {
  341.                     drawAlignedString(g, largestString, x, y, boundx);
  342.  
  343.                     fromIndex = bestpos;
  344.                 }
  345.  
  346.                 y += fm.getHeight();
  347.             }
  348.  
  349.             // We're done with the font metrics...
  350.             fm = null;
  351.         }
  352.     }
  353.  
  354.     /**
  355.      * Adds a listener for all event changes.
  356.      * @param PropertyChangeListener listener the listener to add.
  357.      * @see #removePropertyChangeListener
  358.      */
  359.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  360.     {
  361.         changes.addPropertyChangeListener(listener);
  362.     }
  363.  
  364.     /**
  365.      * Removes a listener for all event changes.
  366.      * @param PropertyChangeListener listener the listener to remove.
  367.      * @see #addPropertyChangeListener
  368.      */
  369.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  370.     {
  371.         changes.removePropertyChangeListener(listener);
  372.     }
  373.  
  374.     /**
  375.      * Adds a vetoable listener for all event changes.
  376.      * @param VetoableChangeListener listener the listener to add.
  377.      * @see #removeVetoableChangeListener
  378.      */
  379.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  380.     {
  381.         vetos.addVetoableChangeListener(listener);
  382.     }
  383.  
  384.     /**
  385.      * Removes a vetoable listener for all event changes.
  386.      * @param VetoableChangeListener listener the listener to remove.
  387.      * @see #addVetoableChangeListener
  388.      */
  389.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  390.     {
  391.         vetos.removeVetoableChangeListener(listener);
  392.     }
  393.  
  394.     /**
  395.      * This helper method draws a string aligned the requested way.
  396.      * @param g the graphics context used for painting
  397.      * @param s the string to draw
  398.      * @param x the point to start drawing from, x coordinate
  399.      * @param y the point to start drawing from, y coordinate
  400.      * @param width the width of the area to draw in, in pixels
  401.      */
  402.     protected void drawAlignedString(Graphics g, String s, int x, int y, int width)
  403.     {
  404.         int drawx;
  405.         int drawy;
  406.  
  407.         drawx = x;
  408.         drawy = y + baseline;
  409.  
  410.         if (align != WrappingLabel.ALIGN_LEFT)
  411.         {
  412.             int sw;
  413.  
  414.             sw = fm.stringWidth(s);
  415.  
  416.             if (align == WrappingLabel.ALIGN_CENTERED)
  417.             {
  418.                 drawx += (width - sw) / 2;
  419.             }
  420.             else if (align == WrappingLabel.ALIGN_RIGHT)
  421.             {
  422.                 drawx = drawx + width - sw;
  423.             }
  424.         }
  425.  
  426.         g.drawString(s, drawx, drawy);
  427.     }
  428.  
  429.     /**
  430.      * The text string being displayed.
  431.      */
  432.     protected String text;
  433.  
  434.     /**
  435.      * The current text alignment.
  436.      * One of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT.
  437.      * @see symantec.itools.awt.AlignStyle
  438.      * @see symantec.itools.awt.AlignStyle#ALIGN_LEFT
  439.      * @see symantec.itools.awt.AlignStyle#ALIGN_CENTERED
  440.      * @see symantec.itools.awt.AlignStyle#ALIGN_RIGHT
  441.      */
  442.     protected int align;
  443.  
  444.     /**
  445.      * The maximum ascent of the font used to display text.
  446.      *
  447.      */
  448.     protected int baseline;
  449.  
  450.     /**
  451.      * The metrics of the font used to display text.
  452.      */
  453.     transient protected FontMetrics fm;
  454.  
  455.     private symantec.itools.beans.VetoableChangeSupport vetos = new symantec.itools.beans.VetoableChangeSupport(this);
  456.     private symantec.itools.beans.PropertyChangeSupport changes = new symantec.itools.beans.PropertyChangeSupport(this);
  457. }
  458.  
  459.